package com.fy.restfulapi.exception;

import com.fy.restfulapi.constant.CommonErrorCode;
import com.fy.restfulapi.response.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.nio.file.AccessDeniedException;

/**
 * @author fengye
 * 基于RestControllerAdvice注解的Controller层的全局异常统一处理
 * 如果项目中集成了springboot Security，配置的RestControllerAdvice全局异常失效了
 * 解决办法：
 * 1、全局异常处理类继承OncePerRequestFilter
 * 2、重写doFilterInternal方法
 * 3、自定义security的bean对象
 */
@Slf4j
@RestControllerAdvice // 相当于@RestControllerAdvice = @ControllerAdvice + @ResponseBody
public class GlobalBaseExceptionHandler {

    /**
     * 参数格式异常处理
     */
    @ExceptionHandler({IllegalArgumentException.class})
    public R<Object> badRequestException(IllegalArgumentException exception) {
        commonPrintError(exception);
        return R.setResult(CommonErrorCode.PARAM_ERROR).message(String.format("参数格式不符(%s)", exception.getMessage()));
    }

    /**
     * 参数缺失异常处理
     */
    @ExceptionHandler({MissingServletRequestParameterException.class})
    public R<Object> badRequestException(Exception exception) {
        commonPrintError(exception);
        return R.setResult(CommonErrorCode.PARAM_ERROR).message(String.format("缺少必传参数(%s)", exception.getMessage()));
    }

    /**
     * 权限不足异常处理
     */
    @ExceptionHandler({AccessDeniedException.class})
    public R<Object> badRequestException(AccessDeniedException exception) {
        commonPrintError(exception);
        return R.setResult(CommonErrorCode.FORBIDDEN);
    }

    /**
     * NoHandlerFoundException 404 异常处理
     */
    @ExceptionHandler({NoHandlerFoundException.class})
    public R<Object> handlerNoHandlerFoundException(NoHandlerFoundException exception) {
        commonPrintError(exception);
        return R.setResult(CommonErrorCode.NOT_FOUND);
    }

    /**
     * 不支持的请求方式异常处理 405
     */
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public R<Object> handlerHttpRequestMethodNotSupportedException(
            HttpRequestMethodNotSupportedException exception) {
        commonPrintError(exception);
        return R.setResult(CommonErrorCode.METHOD_NOT_ALLOWED);
    }

    /**
     * 不支持的媒体类型异常处理 415
     */
    @ExceptionHandler({HttpMediaTypeNotSupportedException.class})
    public R<Object> handlerHttpMediaTypeNotSupportedException(
            HttpMediaTypeNotSupportedException exception) {
        commonPrintError(exception);
        return R.setResult(CommonErrorCode.UNSUPPORTED_MEDIA_TYPE);
    }

    /**
     * 空指针异常
     */
    @ExceptionHandler({NullPointerException.class})
    public R<Object> handleTypeMismatchException(NullPointerException exception) {
        commonPrintError(exception);
        return R.setResult(CommonErrorCode.NULL_POINT);
    }

    /**
     * 通用异常处理方法
     */
    @ExceptionHandler
    public R<Object> handleException(Throwable exception) {
        commonPrintError(exception);
        return R.setResult(CommonErrorCode.INTERNAL_SERVER_ERROR);
    }

    /**
     * 错误统一输出格式
     * @param e
     * @return
     */
    public String commonPrintError(Throwable e) {
        String errmsg = e.getMessage();
        StackTraceElement[] stackTraceElements = e.getStackTrace();
        if (stackTraceElements.length != 0){
            StackTraceElement stackTraceElement = stackTraceElements[0];
            errmsg += "\n" + "问题出处：" + stackTraceElement.toString();
        }

        log.error(errmsg);

        return errmsg;
    }
}
